home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / intrlib1.zip / PU_QUERY.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  27KB  |  713 lines

  1. /******************************************************************************
  2. * Iteraction library - pop up queries.                          *
  3. *                                          *
  4. *                    Written by Gershon Elber,  Oct. 1990  *
  5. *******************************************************************************
  6. * Type of queries currently supported:                          *
  7. * 1. Continue query - informative pop up message. Wait for the user.          *
  8. * 2. Yes/No query - pop up question. Wait for yes/no from the user.          *
  9. * 3. Line query - pop up a messgae. Wait for the user to type a full line.    *
  10. *******************************************************************************
  11. * History:                                      *
  12. *  3 Oct 90 - Version 1.0 by Gershon Elber.                      *
  13. ******************************************************************************/
  14.  
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include "intr_loc.h"
  18. #include "intr_gr.h"
  19.  
  20. #define MIN_CONTINUE_QUERY_WIDTH 150
  21. #define CONTINUE_QUERY_HEIGHT 90
  22. #define CONTINUE_STR_HEIGHT 20
  23. #define CONTINUE_STR_WIDTH 80
  24.  
  25. #define MIN_CONTINUE2_QUERY_WIDTH 150
  26. #define CONTINUE2_QUERY_HEIGHT 40
  27.  
  28. #define MIN_YES_NO_QUERY_WIDTH 180
  29. #define YES_NO_QUERY_HEIGHT 90
  30. #define YES_NO_STR_HEIGHT 20
  31. #define YES_NO_STR_WIDTH 50
  32.  
  33. #define MIN_LINE_QUERY_WIDTH 150
  34. #define LINE_QUERY_HEIGHT 70
  35. #define LINE_WINDOW_LEN 22
  36.  
  37. #define LIST_QUERY_BORDER 8
  38. #ifdef DJGCC
  39. #define LIST_QUERY_BASE_LINE 16
  40. #else
  41. #define LIST_QUERY_BASE_LINE 12
  42. #endif /* DJGCC */
  43.  
  44. static int GRLastColor = 0;               /* GR Color set before query. */
  45. static IntrBType HasHeader = FALSE;
  46.  
  47. static void QueryProlog(int WindowID, int QueryWidth, int QueryHeight,
  48.             IntrCursorShapeStruct *Cursor, IntrColorType FrameWidth,
  49.                         IntrColorType FrameColor, IntrColorType BackColor,
  50.                         int *Xmin, int *Ymin, int *Xmax, int *Ymax,
  51.                         IntrScrlBarType ScrlBar);
  52. static void QueryEpilog(IntrCursorShapeStruct *Cursor);
  53. static int MatchPosition(int x, int y, int Top, int Left,
  54.              int Bottom, int Right, int Space, int ItemHeight);
  55. static void ListQueryDrawItems(char **StrEntries, int SizeOfEntry,
  56.                    int NumOfEntries,
  57.                    int FirstDisplayed, int NumOfDisplayedEntries,
  58.                                int Left, int Top, int Right, int Bottom,
  59.                                IntrColorType BackColor, IntrColorType ForeColor);
  60.  
  61. /****************************************************************************
  62. * Do all common to all queries on entry.                    *
  63. * Attempt will be made to place the message in the middle of the specified  *
  64. * window windowID if possible, or middle of screen if WindowID = 0.        *
  65. * Width and Height specifies the size of the query window and FrameWidth    *
  66. * specifies its FrameWidth. FrameColor and BackColor set the colors.        *
  67. ****************************************************************************/
  68. static void QueryProlog(int WindowID, int QueryWidth, int QueryHeight,
  69.             IntrCursorShapeStruct *Cursor, IntrColorType FrameWidth,
  70.                         IntrColorType FrameColor, IntrColorType BackColor,
  71.                         int *Xmin, int *Ymin, int *Xmax, int *Ymax,
  72.                         IntrScrlBarType ScrlBar)
  73. {
  74.     IntrBBoxStruct *BBox;
  75.     int QueryCenterX, QueryCenterY;
  76.  
  77.     /* Save current graphic state. */
  78.     if (Cursor != NULL) {
  79.         IntrPushCursorType();
  80.         IntrSetCursorType(Cursor);
  81.     }
  82.  
  83.     GRPushViewPort();
  84.     _GRSetViewPort(0, 0, GRScreenMaxX, GRScreenMaxY);
  85.  
  86.     GRPushTextSetting();
  87.     GRSetTextJustify(GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM);
  88.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  89.  
  90.     GRLastColor = GRGetColor();
  91.  
  92.     /* Find center of query prefered position and find BBox for query. */
  93.     if (WindowID > 0) {
  94.         BBox = IntrWndwGetBBox(WindowID);
  95.  
  96.         QueryCenterX = (BBox -> Xmax + BBox -> Xmin) >> 1;
  97.         QueryCenterY = (BBox -> Ymax + BBox -> Ymin) >> 1;
  98.     }
  99.     else
  100.     switch (WindowID) {
  101.         case INTR_WNDW_PLACE_LEFT:
  102.         QueryCenterX = GRScreenMaxX >> 2;
  103.         QueryCenterY = GRScreenMaxY >> 1;
  104.         break;
  105.         case INTR_WNDW_PLACE_RIGHT:
  106.         QueryCenterX = (GRScreenMaxX >> 1) + (GRScreenMaxX >> 2);
  107.         QueryCenterY = GRScreenMaxY >> 1;
  108.         break;
  109.         case INTR_WNDW_PLACE_CENTER:
  110.         default:
  111.         QueryCenterX = GRScreenMaxX >> 1;
  112.         QueryCenterY = GRScreenMaxY >> 1;
  113.         break;
  114.     }
  115.  
  116.     *Xmin = QueryCenterX - (QueryWidth >> 1);
  117.     *Ymin = QueryCenterY - (QueryHeight >> 1);
  118.     *Xmax = *Xmin + QueryWidth;
  119.     *Ymax = *Ymin + QueryHeight;
  120.     _IntrBoundBBox(Xmin, Ymin, Xmax, Ymax, FrameWidth); /* To screen coords. */
  121.  
  122.     _IntrWndwDrawFrame(*Xmin, *Xmax, *Ymin, *Ymax, FrameWidth,
  123.                FrameColor, TRUE, FrameColor, INTR_SCRLBAR_NONE,
  124.                        FrameColor, ScrlBar, TRUE);
  125.     IntrAllocColor(BackColor, INTR_INTENSITY_HIGH);
  126.     GRSBar(*Xmin, *Ymin, *Xmax, *Ymax);
  127. }
  128.  
  129. /****************************************************************************
  130. * Pop current graphic state.                            *
  131. ****************************************************************************/
  132. static void QueryEpilog(IntrCursorShapeStruct *Cursor)
  133. {
  134.     if (_IntrSaveBelow) {
  135.     _IntrRestoreWindow();
  136.         if (HasHeader) {
  137.             _IntrRestoreWindow();
  138.             HasHeader = FALSE;
  139.         }
  140.     }
  141.  
  142.     GRPopViewPort();
  143.     GRPopTextSetting();
  144.     GRSetColor(GRLastColor);
  145.  
  146.     if (Cursor != NULL)
  147.     IntrPopCursorType();
  148. }
  149.  
  150. /****************************************************************************
  151. * Perform simple clipping and translation to make sure entire bbox is in    *
  152. * the screen boundary.                                *
  153. ****************************************************************************/
  154. void _IntrBoundBBox(int *Xmin, int *Ymin, int *Xmax, int *Ymax, int Width)
  155. {
  156.     if (*Xmin < Width) {
  157.     *Xmax -= *Xmin - Width;
  158.         *Xmin = Width;
  159.     }
  160.     if (*Xmax > GRScreenMaxX - Width) {
  161.     *Xmin -= *Xmax - GRScreenMaxX + Width;
  162.         *Xmax = GRScreenMaxX - Width;
  163.     }
  164.     if (*Ymin < Width) {
  165.     *Ymax -= *Ymin - Width;
  166.         *Ymin = Width;
  167.     }
  168.     if (*Ymax > GRScreenMaxY - Width) {
  169.     *Ymin -= *Ymax - GRScreenMaxY + Width;
  170.         *Ymax = GRScreenMaxY - Width;
  171.     }
  172. }
  173.  
  174. /****************************************************************************
  175. * Routine to display one string and return after a continue button has been *
  176. * pressed. Used to inform the user on some status.                *
  177. * Attempt will be made to place the message in the middle of the specified  *
  178. * window if possible, or middle of screen if WindowID = 0.            *
  179. ****************************************************************************/
  180. void IntrQueryContinue(char *Question,
  181.                IntrColorType FrameColor,
  182.                IntrColorType BackColor,
  183.                IntrColorType ForeColor,
  184.                IntrColorType XorColor,
  185.                        int FrameWidth,
  186.                        IntrCursorShapeStruct *Cursor,
  187.                        int WindowID)
  188. {
  189.     IntrEventType Event;
  190.     int x, y, TextWidth, NewMatch, Color, QueryWidth, QueryHeight,
  191.     Xmin, Ymin, Xmax, Ymax, ContXmin, ContYmin, ContXmax, ContYmax,
  192.     Exit = FALSE,
  193.         Match = -1;
  194.  
  195.     GRPushTextSetting();
  196.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  197.     TextWidth = GRGetTextWidth(Question);
  198.     QueryWidth = MAX(TextWidth + 10, MIN_CONTINUE_QUERY_WIDTH);
  199.     QueryHeight = CONTINUE_QUERY_HEIGHT;
  200.     GRPopTextSetting();
  201.  
  202.     QueryProlog(WindowID, QueryWidth, QueryHeight, Cursor, FrameWidth,
  203.             FrameColor, BackColor, &Xmin, &Ymin, &Xmax, &Ymax,
  204.         INTR_SCRLBAR_NONE);
  205.  
  206.     /* Compute spaces between the Continue button and question. */
  207.     y = ((Ymax - Ymin) - CONTINUE_STR_HEIGHT - GRGetTextHeight(Question)) / 3;
  208.  
  209.     /* Draw the "continue" button. */
  210.     ContXmin = (Xmin + Xmax - CONTINUE_STR_WIDTH) >> 1;
  211.     ContXmax = (Xmin + Xmax + CONTINUE_STR_WIDTH) >> 1;
  212.     ContYmax = Ymax - y;
  213.     ContYmin = ContYmax - CONTINUE_STR_HEIGHT;
  214.     _IntrWndwDrawFrame(ContXmin, ContXmax, ContYmin, ContYmax, FrameWidth,
  215.                FrameColor, FALSE, FrameColor, INTR_SCRLBAR_NONE,
  216.                        FrameColor, INTR_SCRLBAR_NONE, TRUE);
  217.     IntrAllocColor(BackColor, INTR_INTENSITY_LOW);
  218.     GRSBar(ContXmin, ContYmin, ContXmax, ContYmax);
  219.     Color = IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH);
  220.     GRSetTextJustify(GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER);
  221.  
  222.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  223.     GRSTextShadow((ContXmin + ContXmax) >> 1, (ContYmin + ContYmax) >> 1,
  224.          Color, "Continue");
  225.  
  226.     /* Put the question in: */
  227.     GRSTextShadow((Xmin + Xmax) >> 1, Ymin + y,  Color, Question);
  228.  
  229.     /* Put the mouse on the middle of the CONTINUE box: */
  230.     x = GRCurrentCursorX = (ContXmin + ContXmax) >> 1;
  231.     y = GRCurrentCursorY = (ContYmin + ContYmax) >> 1;
  232.     Event = INTR_EVNT_MOVE;/* Emulate move event, and test current position. */
  233.  
  234.     while (!Exit) {
  235.     switch (Event) {
  236.         case INTR_EVNT_KEY:
  237.         if (x == 'c' || x == 'C') {
  238.             Match = 1;
  239.             Exit = TRUE;
  240.             break;
  241.         }
  242.         break;
  243.         case INTR_EVNT_SELECT:
  244.         if (Match >= 0)
  245.             Exit = TRUE;
  246.         else {
  247.             GRTone(1000, 100);             /* Do some noise... */
  248.             GRTone( 300, 200);
  249.         }
  250.         break;
  251.         case INTR_EVNT_ABORT:                     /* Ignored. */
  252.         GRTone(1000, 100);             /* Do some noise... */
  253.         GRTone( 300, 200);
  254.         break;
  255.         case INTR_EVNT_MOVE:
  256.         if (x >= ContXmin && x <= ContXmax &&
  257.             y >= ContYmin && y <= ContYmax)
  258.             NewMatch = 1;
  259.         else
  260.             NewMatch = -1;                /* No match. */
  261.         if (NewMatch != Match) {
  262.                 IntrAllocColor(XorColor, INTR_INTENSITY_VHIGH);
  263.  
  264.             /* If something was selected before - uninvert it: */
  265.             if (Match == 1)
  266.             GRXORRectangle(ContXmin, ContYmin, ContXmax, ContYmax);
  267.             Match = NewMatch;
  268.  
  269.             /*Invert new selection if there is one: */
  270.             if (Match == 1)
  271.             GRXORRectangle(ContXmin, ContYmin, ContXmax, ContYmax);
  272.         }
  273.         break;
  274.     }
  275.     if (!Exit) Event = IntrGetEventWait(&x, &y);
  276.     }
  277.  
  278.     QueryEpilog(Cursor);
  279. }
  280.  
  281. /****************************************************************************
  282. * Same as continue but call ExecFunc instead of event waiting.            *
  283. ****************************************************************************/
  284. void IntrQueryContinue2(char *Question,
  285.             void (* ExecFunc)(void),
  286.                 IntrColorType FrameColor,
  287.                 IntrColorType BackColor,
  288.                 IntrColorType ForeColor,
  289.                         int FrameWidth,
  290.                         IntrCursorShapeStruct *Cursor,
  291.                         int WindowID)
  292. {
  293.     int TextWidth, QueryWidth, QueryHeight, Xmin, Ymin, Xmax, Ymax;
  294.  
  295.     GRPushTextSetting();
  296.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  297.     TextWidth = GRGetTextWidth(Question);
  298.     QueryWidth = MAX(TextWidth + 10, MIN_CONTINUE2_QUERY_WIDTH);
  299.     QueryHeight = CONTINUE2_QUERY_HEIGHT;
  300.     GRPopTextSetting();
  301.  
  302.     QueryProlog(WindowID, QueryWidth, QueryHeight, Cursor,
  303.             FrameWidth, FrameColor, BackColor, &Xmin, &Ymin, &Xmax, &Ymax,
  304.         INTR_SCRLBAR_NONE);
  305.  
  306.     /* Put the question in: */
  307.     GRSetTextJustify(GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER);
  308.     GRSTextShadow((Xmin + Xmax) >> 1, (Ymin + Ymax) >> 1,
  309.          IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH), Question);
  310.  
  311.     ExecFunc();
  312.  
  313.     QueryEpilog(Cursor);
  314. }
  315.  
  316. /****************************************************************************
  317. * Routine to display one string and return TRUE if YES is selected FALSE if *
  318. * NO. select must be made using the Select key, and Abort key is ignored.   *
  319. * Attempt will be made to place the message in the middle of the specified  *
  320. * window if possible, or middle of screen if WindowID = 0.            *
  321. ****************************************************************************/
  322. IntrBType IntrQueryYesNo(char *Question,
  323.                  IntrColorType FrameColor,
  324.                  IntrColorType BackColor,
  325.                  IntrColorType ForeColor,
  326.                  IntrColorType XorColor,
  327.                          int FrameWidth,
  328.                          IntrCursorShapeStruct *Cursor,
  329.                          int WindowID)
  330. {
  331.     IntrEventType Event;
  332.     int x, y, TextWidth, Color, NewMatch, QueryWidth, QueryHeight,
  333.     Xmin, Ymin, Xmax, Ymax, Dx4, YesXmin, YesYmin, YesXmax, YesYmax,
  334.     NoXmin, NoYmin, NoXmax, NoYmax,
  335.     Exit = FALSE,
  336.     Match = -1;
  337.  
  338.     GRPushTextSetting();
  339.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  340.     TextWidth = GRGetTextWidth(Question);
  341.     QueryWidth = MAX(TextWidth + 10, MIN_YES_NO_QUERY_WIDTH);
  342.     QueryHeight = YES_NO_QUERY_HEIGHT;
  343.     GRPopTextSetting();
  344.  
  345.     QueryProlog(WindowID, QueryWidth, QueryHeight, Cursor,
  346.             FrameWidth, FrameColor, BackColor, &Xmin, &Ymin, &Xmax, &Ymax,
  347.         INTR_SCRLBAR_NONE);
  348.  
  349.     Dx4 = (Xmax - Xmin) >> 2;
  350.  
  351.     y = ((Ymax - Ymin) - YES_NO_STR_HEIGHT - GRGetTextHeight(Question)) / 3;
  352.  
  353.     /* Draw the "yes" button. */
  354.     YesXmin = Xmin + Dx4 - (YES_NO_STR_WIDTH >> 1);
  355.     YesXmax = Xmin + Dx4 + (YES_NO_STR_WIDTH >> 1);
  356.     YesYmax = Ymax - y;
  357.     YesYmin = YesYmax - YES_NO_STR_HEIGHT;
  358.     _IntrWndwDrawFrame(YesXmin, YesXmax, YesYmin, YesYmax, FrameWidth,
  359.                FrameColor, FALSE, FrameColor, INTR_SCRLBAR_NONE,
  360.                        FrameColor, INTR_SCRLBAR_NONE, TRUE);
  361.     IntrAllocColor(BackColor, INTR_INTENSITY_LOW);
  362.     GRSBar(YesXmin, YesYmin, YesXmax, YesYmax);
  363.     Color = IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH);
  364.     GRSetTextJustify(GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER);
  365.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  366.     GRSTextShadow((YesXmin + YesXmax) >> 1, (YesYmin + YesYmax) >> 1,
  367.                                 Color, "Yes");
  368.  
  369.     /* Draw the "no" button. */
  370.     NoXmin = Xmax - Dx4 - (YES_NO_STR_WIDTH >> 1);
  371.     NoXmax = Xmax - Dx4 + (YES_NO_STR_WIDTH >> 1);
  372.     NoYmax = Ymax - y;
  373.     NoYmin = NoYmax - YES_NO_STR_HEIGHT;
  374.     _IntrWndwDrawFrame(NoXmin, NoXmax, NoYmin, NoYmax, FrameWidth,
  375.                FrameColor, FALSE, FrameColor, INTR_SCRLBAR_NONE,
  376.                        FrameColor, INTR_SCRLBAR_NONE, TRUE);
  377.     IntrAllocColor(BackColor, INTR_INTENSITY_LOW);
  378.     GRSBar(NoXmin, NoYmin, NoXmax, NoYmax);
  379.     GRSetTextJustify(GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER);
  380.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  381.     GRSTextShadow((NoXmin + NoXmax) >> 1, (NoYmin + NoYmax) >> 1, Color, "No");
  382.  
  383.     /* Put the question in: */
  384.     GRSTextShadow((Xmin + Xmax) >> 1, Ymin + y, Color, Question);
  385.  
  386.     /* Put the mouse on the middle of the Yes box: */
  387.     x = GRCurrentCursorX = (YesXmin + YesXmax) >> 1;
  388.     y = GRCurrentCursorY = (YesYmin + YesYmax) >> 1;
  389.     Event = INTR_EVNT_MOVE;/* Emulate move event, and test current position. */
  390.  
  391.     while (!Exit) {
  392.     switch (Event) {
  393.         case INTR_EVNT_KEY:
  394.         if (x == 'y' || x == 'Y') {
  395.             Match = 1;
  396.             Exit = TRUE;
  397.             break;
  398.         }
  399.         if (x == 'n' || x == 'N') {
  400.             Match = 0;
  401.             Exit = TRUE;
  402.             break;
  403.         }
  404.         break;
  405.         case INTR_EVNT_SELECT:
  406.         if (Match >= 0)
  407.             Exit = TRUE;
  408.         else {
  409.             GRTone(1000, 100);             /* Do some noise... */
  410.             GRTone( 300, 200);
  411.         }
  412.         break;
  413.         case INTR_EVNT_ABORT:                     /* Ignored. */
  414.         GRTone(1000, 100);             /* Do some noise... */
  415.         GRTone( 300, 200);
  416.         break;
  417.         case INTR_EVNT_MOVE:
  418.         if (x >= YesXmin && x <= YesXmax &&
  419.                     y >= YesYmin && y <= YesYmax)
  420.             NewMatch = 1;
  421.         else if (x >= NoXmin && x <= NoXmax &&
  422.                  y >= NoYmin && y <= NoYmax)
  423.             NewMatch = 0;
  424.         else
  425.             NewMatch = -1;                /* No match. */
  426.         if (NewMatch != Match) {
  427.                 IntrAllocColor(XorColor, INTR_INTENSITY_VHIGH);
  428.  
  429.             /* If something was selected before - uninvert it: */
  430.             if (Match == 0)
  431.                 GRXORRectangle(NoXmin, NoYmin, NoXmax, NoYmax);
  432.             else if (Match == 1)
  433.                 GRXORRectangle(YesXmin, YesYmin, YesXmax, YesYmax);
  434.  
  435.             Match = NewMatch;
  436.  
  437.             /* If something is selected now - invert it: */
  438.             if (Match == 0)
  439.                 GRXORRectangle(NoXmin, NoYmin, NoXmax, NoYmax);
  440.             else if (Match == 1)
  441.                 GRXORRectangle(YesXmin, YesYmin, YesXmax, YesYmax);
  442.         }
  443.         break;
  444.     }
  445.     if (!Exit) Event = IntrGetEventWait(&x, &y);
  446.     }
  447.  
  448.     QueryEpilog(Cursor);
  449.  
  450.     return Match;
  451. }
  452.  
  453. /****************************************************************************
  454. * Routine to display one string and wait for input string, which is         *
  455. * placed in given buffer. String may be non NULL to begin with.            *
  456. * Attempt will be made to place the message in the middle of the specified  *
  457. * window if possible, or middle of screen if WindowID = 0.            *
  458. * Return the Buffer address.                            *
  459. ****************************************************************************/
  460. char *IntrQueryLine(char *Question,
  461.             char *Buffer,
  462.                     int BufferSize,
  463.             IntrColorType FrameColor,
  464.             IntrColorType BackColor,
  465.             IntrColorType ForeColor,
  466.                     int FrameWidth,
  467.                     int WindowID)
  468. {
  469.     int x, y, LineWindowLen, TextWidth, QueryWidth, QueryHeight, Color,
  470.         Xmin, Ymin, Xmax, Ymax;
  471.  
  472.     GRPushTextSetting();
  473.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  474.     TextWidth = GRGetTextWidth(Question);
  475.     QueryWidth = MAX(TextWidth + 10, MIN_LINE_QUERY_WIDTH);
  476.     QueryHeight = LINE_QUERY_HEIGHT;
  477.     GRPopTextSetting();
  478.  
  479.     QueryProlog(WindowID, QueryWidth, QueryHeight, NULL,
  480.             FrameWidth, FrameColor, BackColor, &Xmin, &Ymin, &Xmax, &Ymax,
  481.         INTR_SCRLBAR_NONE);
  482.  
  483.     /* Put underline for input line: */
  484.     x = Xmin + 20;
  485.     y = Ymax - ((Ymax - Ymin) >> 2) - 10; 
  486.  
  487.     GRSetTextJustify(GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER);
  488.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  489.     Color = IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH);
  490.  
  491.     /* Put the question in: */
  492.     GRSTextShadow((Xmin + Xmax) >> 1, Ymin + ((Ymax - Ymin) >> 2), Color,
  493.                                 Question);
  494.  
  495.     LineWindowLen = (Xmax - Xmin - 40) / GRGetTextWidth("M");
  496.     GRSLine(x,
  497.             y + GRGetTextHeight("M") + 3,
  498.         x + GRGetTextWidth("M") * LineWindowLen,
  499.             y + GRGetTextHeight("M") + 3);
  500.  
  501.     GRGetGraphicLine(0, x, y, Buffer, BufferSize, LineWindowLen,
  502.              IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH),
  503.              IntrAllocColor(BackColor, INTR_INTENSITY_HIGH));
  504.  
  505.     QueryEpilog(NULL);
  506.  
  507.     return Buffer;
  508. }
  509.  
  510. /****************************************************************************
  511. * Routine to attempt to match given location with one of the elements in    *
  512. * items displayed. Item are displayed from Top to Bottom, Left to Right.    *
  513. * Item is placed with Space between them and border, and has ItemHeight     *
  514. * height.                                    *
  515. * Returns the index that matches, or -1 if No match.                *
  516. ****************************************************************************/
  517. static int MatchPosition(int x, int y, int Top, int Left,
  518.              int Bottom, int Right, int Space, int ItemHeight)
  519. {
  520.     int CurrentY, i;
  521.  
  522.     /* Fast clipping if cursor is not in the menu at all. */
  523.     if (x <= Left || x >= Right || y <= Top || y >= Bottom) return -1;
  524.  
  525.     for (i = 0, CurrentY = Top;
  526.      CurrentY < Bottom;
  527.      CurrentY += Space, i++) {
  528.     if (CurrentY <= y && CurrentY + ItemHeight >= y) return i;
  529.     }
  530.     return -1;
  531. }
  532.  
  533. /****************************************************************************
  534. * Routine to display a list of items and pick one of them. Functionality    *
  535. * of this query is very much like a pop up menu, but number of items is     *
  536. * virtually unlimited - the user can scroll between items.            *
  537. * Header is an optional header for the list query.                *
  538. * StrEntries may be an array of (char *) in which SizeOfEntry is 0 or may   *
  539. * be of type (char *) itself and it will hold all items linearly, each of   *
  540. * size SizeOfEntry.                                      *
  541. * NumOfEntries holds number of entries in StrEntries - List size.        *
  542. * NumOfDisplayedEntries holds # of entries to be simultaneously displayed.  *
  543. * XXXXColor controls different colors to be used.                *
  544. * FrameWidth sets the frame drawn for the list query width.            *
  545. * Cursor may specify a new cursor to use.                    *
  546. * Menu will be poped in the middle of the screen if WindowID == 0 or in the *
  547. * middle of the specified WindowID. In all cases the menu will be moved so  *
  548. * it will be all visible.                            *
  549. ****************************************************************************/
  550. int IntrQueryList(char *Header,
  551.           char **StrEntries,
  552.           int SizeOfEntry,
  553.                   int NumOfEntries,
  554.                   int NumOfDisplayedEntries,
  555.           IntrColorType FrameColor,
  556.           IntrColorType BackColor,
  557.           IntrColorType ForeColor,
  558.           IntrColorType XorColor,
  559.           int FrameWidth,
  560.                   IntrCursorShapeStruct *Cursor,
  561.                   int WindowID)
  562. {
  563.     int i, MaxLen, QueryWidth, QueryHeight, Xmin, Xmax, Ymin, Ymax, NewIndex,
  564.         x, y, Event, RetVal, ListLeft, ListTop, ListRight, ListBottom,
  565.         MatchIndex = -1,
  566.         FirstDisplayed = 0;
  567.     IntrBType
  568.         Exit = FALSE;
  569.     IntrRType
  570.         DisplayedFraction = ((IntrRType) NumOfDisplayedEntries) / NumOfEntries,
  571.         RelativePosition = 0.0;
  572.     char
  573.         *String = (char *) StrEntries;
  574.  
  575.     /* Find width and height of list query using number of items and their   */
  576.     /* maximum entry string length.                         */
  577.     if (SizeOfEntry == 0) {          /* Its an array of pointers to strings. */
  578.         for (i = MaxLen = 0; i < NumOfEntries; i++)
  579.             if (MaxLen < strlen(StrEntries[i]))
  580.                 MaxLen = strlen(StrEntries[i]);
  581.     }
  582.     else {
  583.         for (i = MaxLen = 0; i < NumOfEntries; i++)
  584.             if (MaxLen < strlen(&String[i * SizeOfEntry]))
  585.                 MaxLen = strlen(&String[i * SizeOfEntry]);
  586.     }
  587.  
  588.     GRPushTextSetting();
  589.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  590.     QueryWidth = GRGetTextWidth("M") * MaxLen + (LIST_QUERY_BORDER << 1);
  591.     QueryHeight = NumOfDisplayedEntries * LIST_QUERY_BASE_LINE +
  592.                                   (LIST_QUERY_BORDER << 1);
  593.     GRPopTextSetting();
  594.  
  595.     QueryProlog(WindowID, QueryWidth, QueryHeight, Cursor,
  596.             FrameWidth, FrameColor,    BackColor, &Xmin, &Ymin, &Xmax, &Ymax,
  597.         INTR_SCRLBAR_LEFT);
  598.  
  599.     MatchIndex = -1;                      /* No match == -1. */
  600.     ListLeft = Xmin + LIST_QUERY_BORDER;
  601.     ListTop = Ymin + LIST_QUERY_BORDER;
  602.     ListRight = Xmax - LIST_QUERY_BORDER;
  603.     ListBottom = Ymax - LIST_QUERY_BORDER;
  604.  
  605.     ListQueryDrawItems(StrEntries, SizeOfEntry, NumOfEntries,
  606.                    FirstDisplayed, NumOfDisplayedEntries,
  607.                        ListLeft, ListTop, ListRight, ListBottom,
  608.                        BackColor, ForeColor);
  609.     if (Header != NULL) {
  610.     HasHeader = TRUE;
  611.     _IntrWndwPutNameHeader(Xmin - FrameWidth - _INTR_SCROLL_BAR_WIDTH - 1,
  612.                    Xmax + FrameWidth,
  613.                                Ymin - FrameWidth - 2,
  614.                                FrameWidth, Header, TRUE, FrameColor,
  615.                                ForeColor, BackColor, TRUE);
  616.     }
  617.  
  618.     _IntrUpdateScrollBar(Xmin - _INTR_SCROLL_BAR_WIDTH - 1, Ymin,
  619.                  Xmin - 1, Ymax,
  620.                          RelativePosition, DisplayedFraction, TRUE, ForeColor);
  621.  
  622.     Event = INTR_EVNT_MOVE;/* Emulate move event, and test current position. */
  623.     x = GRCurrentCursorX = (ListLeft + ListRight) >> 1;
  624.     y = GRCurrentCursorY = (ListTop + ListBottom) >> 1;
  625.     while (!Exit) {
  626.     switch (Event) {
  627.         case INTR_EVNT_SELECT:
  628.         /* We are on list item - need to return its index. */
  629.         if (MatchIndex >= 0) {
  630.             RetVal = MatchIndex + FirstDisplayed;
  631.             Exit = TRUE;
  632.         }
  633.         else if (x >= Xmin - _INTR_SCROLL_BAR_WIDTH && x <= Xmin &&
  634.              y >= Ymin && y <= Ymax) {
  635.                     RelativePosition = ((IntrRType) (y - Ymin)) /
  636.                                                (Ymax - Ymin);
  637.                     FirstDisplayed = (int) (RelativePosition * NumOfEntries);
  638.                     _IntrUpdateScrollBar(Xmin - _INTR_SCROLL_BAR_WIDTH - 1, Ymin,
  639.                                  Xmin - 1, Ymax,
  640.                                          RelativePosition, DisplayedFraction,
  641.                                          TRUE, ForeColor);
  642.             ListQueryDrawItems(StrEntries, SizeOfEntry, NumOfEntries,
  643.                                    FirstDisplayed, NumOfDisplayedEntries,
  644.                                ListLeft, ListTop, ListRight, ListBottom,
  645.                                       BackColor, ForeColor);
  646.         }
  647.         break;
  648.         case INTR_EVNT_ABORT:
  649.         RetVal = -1;
  650.         Exit = TRUE;
  651.         break;
  652.         case INTR_EVNT_MOVE:
  653.             IntrAllocColor(XorColor, INTR_INTENSITY_VHIGH);
  654.         NewIndex = MatchPosition(x, y,
  655.                     ListTop, ListLeft, ListBottom, ListRight,
  656.                     LIST_QUERY_BASE_LINE, GRGetTextHeight("M"));
  657.         if (NewIndex + FirstDisplayed >= NumOfEntries)
  658.                     NewIndex = -1;
  659.  
  660.         if (NewIndex != MatchIndex) {
  661.             /* Invert this entry back to original state: */
  662.             if (MatchIndex >= 0)
  663.             GRXORRectangle(ListLeft - 1,
  664.                            ListTop + MatchIndex * LIST_QUERY_BASE_LINE - 1,
  665.                        ListRight + 1,
  666.                            ListTop + GRGetTextHeight("M") + 1 +
  667.                                               MatchIndex * LIST_QUERY_BASE_LINE);
  668.             MatchIndex = NewIndex;
  669.             /* Invert this entry: */
  670.             if (MatchIndex >= 0)
  671.             GRXORRectangle(ListLeft - 1,
  672.                            ListTop + MatchIndex * LIST_QUERY_BASE_LINE - 1,
  673.                        ListRight + 1,
  674.                            ListTop + GRGetTextHeight("M") + 1 +
  675.                                               MatchIndex * LIST_QUERY_BASE_LINE);
  676.         }
  677.         break;
  678.     }
  679.     if (!Exit) Event = IntrGetEventWait(&x, &y);
  680.     }
  681.  
  682.     QueryEpilog(Cursor);
  683.  
  684.     return RetVal;
  685. }
  686.  
  687. /****************************************************************************
  688. * Routine to display list of items in the given location and spacing:        *
  689. * All list and area is inverted once drawn.                    *
  690. * If SizeOfItem = 0 then Items is assumed to point on array of (char *).    *
  691. ****************************************************************************/
  692. static void ListQueryDrawItems(char **StrEntries, int SizeOfEntry,
  693.                    int NumOfEntries,
  694.                    int FirstDisplayed, int NumOfDisplayedEntries,
  695.                                int Left, int Top, int Right, int Bottom,
  696.                                IntrColorType BackColor, IntrColorType ForeColor)
  697. {
  698.     int i, Last, Color;
  699.     char
  700.         *String = (char *) StrEntries;
  701.  
  702.     IntrAllocColor(BackColor, INTR_INTENSITY_HIGH);
  703.     GRSBar(Left - 2, Top, Right, Bottom + 1);   /* -2, +1 because of shadow. */
  704.  
  705.     Last = MIN(NumOfEntries, FirstDisplayed + NumOfDisplayedEntries);
  706.     Color = IntrAllocColor(ForeColor, INTR_INTENSITY_VHIGH);
  707.     GRSetTextJustify(GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP);
  708.     for (i = FirstDisplayed; i < Last; i++)
  709.     GRSTextShadow(Left, Top + (i - FirstDisplayed) * LIST_QUERY_BASE_LINE,
  710.         Color,
  711.         SizeOfEntry == 0 ? StrEntries[i] : &String[i * SizeOfEntry]);
  712. }
  713.